﻿using System.IO;
using Moq;
using NUnit.Framework;

namespace PhotoFramePublishingPlugin.Tests
{
    [TestFixture]
    public class ConfigurationSettingsPresenterBrowseForFolderTests
    {
        const string InitialDestinationRoot = @"D:\Temp";
        const string ExpectedDestinationRoot = @"C:\Temp";
        const string InvalidDestinationRoot = @"D:\Temp\PhotoFramePublishingPlugin";

        [SetUp]
        public void SetUp()
        {
            if (Directory.Exists(InvalidDestinationRoot))
                Directory.Delete(InvalidDestinationRoot);
        }

        [Test]
        public void WithDestinationRoot_BrowseForFolder_Cancelled_DoesntChangeDestinationRoot()
        {
            Mock<IConfigurationSettingsView> view = new Mock<IConfigurationSettingsView>(MockBehavior.Strict);
            ConfigurationSettingsModel model = new ConfigurationSettingsModel(800, 600, InitialDestinationRoot, false, false);

            ConfigurationSettingsPresenter presenter = new ConfigurationSettingsPresenter(view.Object, model);

            Mock<IFolderBrowserFactory> folderBrowserFactory = new Mock<IFolderBrowserFactory>(MockBehavior.Strict);
            folderBrowserFactory.SetupProperty(f => f.Description);
            folderBrowserFactory.SetupProperty(f => f.SelectedPath);
            folderBrowserFactory.Setup(f => f.ShowDialog()).Returns(false);

            bool result = presenter.BrowseForFolder(folderBrowserFactory.Object);
            Assert.IsFalse(result);

            Assert.AreEqual(InitialDestinationRoot, presenter.DestinationRoot);
        }

        [Test]
        public void WithDestinationRoot_BrowseForFolder_Confirmed_ChangesDestinationRoot_RaisesPropertyChanged()
        {
            Mock<IConfigurationSettingsView> view = new Mock<IConfigurationSettingsView>(MockBehavior.Strict);
            view.SetupProperty(v => v.OkButtonEnabled);
            view.Setup(v => v.ClearDestinationError());
            view.Setup(v => v.SetBorderPreview(It.IsAny<BorderPreviewMode>()));

            ConfigurationSettingsModel model = new ConfigurationSettingsModel(800, 600, InitialDestinationRoot, false, false);

            ConfigurationSettingsPresenter presenter = new ConfigurationSettingsPresenter(view.Object, model);

            bool propertyChangedWasRaised = false;
            presenter.PropertyChanged += (sender, e) => { Assert.AreEqual("DestinationRoot", e.PropertyName); propertyChangedWasRaised = true; };

            Mock<IFolderBrowserFactory> folderBrowserFactory = new Mock<IFolderBrowserFactory>(MockBehavior.Strict);
            folderBrowserFactory.SetupProperty(f => f.Description);
            folderBrowserFactory.SetupProperty(f => f.SelectedPath);
            folderBrowserFactory.Setup(f => f.ShowDialog())
                .Callback(() => folderBrowserFactory.SetupGet(f => f.SelectedPath).Returns(ExpectedDestinationRoot))
                .Returns(true);

            bool result = presenter.BrowseForFolder(folderBrowserFactory.Object);
            Assert.IsTrue(result);

            Assert.That(propertyChangedWasRaised);
            Assert.AreEqual(ExpectedDestinationRoot, presenter.DestinationRoot);
        }

        [Test]
        public void WithDestinationRoot_SetInvalidDestinationRoot_SetsError()
        {
            Mock<IConfigurationSettingsView> view = new Mock<IConfigurationSettingsView>(MockBehavior.Strict);
            view.SetupProperty(v => v.OkButtonEnabled);
            view.Setup(v => v.ClearDestinationError());
            view.Setup(v => v.SetDestinationError(It.IsAny<string>())).Verifiable();
            view.Setup(v => v.SetBorderPreview(It.IsAny<BorderPreviewMode>()));

            ConfigurationSettingsModel model = new ConfigurationSettingsModel(800, 600, InitialDestinationRoot, false, false);

            ConfigurationSettingsPresenter presenter = new ConfigurationSettingsPresenter(view.Object, model);
            presenter.DestinationRoot = InvalidDestinationRoot;

            view.Verify();
        }

        [Test]
        public void WithInvalidDestinationRoot_BrowseAndCreateFolder_Confirmed_ClearsError()
        {
            Mock<IConfigurationSettingsView> view = new Mock<IConfigurationSettingsView>(MockBehavior.Strict);
            view.SetupProperty(v => v.OkButtonEnabled);
            view.Setup(v => v.ClearDestinationError());
            view.Setup(v => v.SetDestinationError(It.IsAny<string>())).Verifiable();
            view.Setup(v => v.SetBorderPreview(It.IsAny<BorderPreviewMode>()));

            ConfigurationSettingsModel model = new ConfigurationSettingsModel(800, 600, InitialDestinationRoot, false, false);

            ConfigurationSettingsPresenter presenter = new ConfigurationSettingsPresenter(view.Object, model);
            presenter.DestinationRoot = InvalidDestinationRoot;

            view.Verify();

            // We're now expecting this to be called.
            bool clearDestinationErrorWasCalled = false;
            view.Setup(v => v.ClearDestinationError()).Callback(() => clearDestinationErrorWasCalled = true);

            Mock<IFolderBrowserFactory> folderBrowserFactory = new Mock<IFolderBrowserFactory>(MockBehavior.Strict);
            folderBrowserFactory.SetupProperty(f => f.Description);
            folderBrowserFactory.SetupProperty(f => f.SelectedPath);
            folderBrowserFactory.Setup(f => f.ShowDialog())
                .Callback(() =>
                {
                    // Create the directory so that it now exists.
                    Directory.CreateDirectory(InvalidDestinationRoot);
                    folderBrowserFactory.SetupGet(f => f.SelectedPath).Returns(InvalidDestinationRoot);
                })
                .Returns(true);

            bool result = presenter.BrowseForFolder(folderBrowserFactory.Object);
            Assert.IsTrue(result, "BrowseForFolder returned false");
            Assert.IsTrue(clearDestinationErrorWasCalled, "ClearDestinationError was not called");

            Assert.AreEqual(InvalidDestinationRoot, presenter.DestinationRoot);
        }
    }
}